package com.congwulin.wechat.util.service.bill;

import com.congwulin.wechat.entity.common.AbstractMeBillVO;
import com.congwulin.wechat.entity.common.SuperVO;
import com.congwulin.wechat.util.*;
import com.congwulin.wechat.util.interfaces.IBillPersistent;
import com.congwulin.wechat.util.interfaces.IVOPersistent;
import com.congwulin.wechat.util.service.vo.VOPersistent;

import java.util.*;

/**
 * 一主多子数据库持久化实现
 */
public class BillPersistent implements IBillPersistent {

    /**
     * 实体类对应的实体数据库保存器
     */
    private Map<Class<?>, VOPersistent> daoIndex = new HashMap<Class<?>, VOPersistent>();

    /**
     * 按照实体类型注册实体数据库保存
     *
     * @param clazz 实体类型
     * @param persistent 实体保存数据库访问器
     */
    public void regiter(Class<?> clazz, IVOPersistent persistent) {
        VOPersistent voPersistent = new VOPersistent(persistent);
        this.daoIndex.put(clazz, voPersistent);
    }

    private void setIDAndFK(AbstractMeBillVO bill) {
        //设置主实体主键
        SuperVO head = bill.getHead();
        String id = head.getId();
        if (id == null) {
            id = UUID.randomUUID().toString().replaceAll("-", "");
        }
        head.setId(id);

        //设置子实体的外键（主实体主键）
        Map<Class<?>, String> fkIndex = bill.getChildrenFK();
        Map<String, Class<?>> areaIndex = bill.getAreaNameIndex();
        Set<Map.Entry<String, Class<?>>> set = areaIndex.entrySet();
        for (Map.Entry<String, Class<?>> entry : set) {
            Class<?> clazz = entry.getValue();
            List<SuperVO> childlist = bill.getChildren(clazz);
            ClassField fk = null;
            if (fkIndex.containsKey(clazz)) {
                fk = this.getFKField(clazz, fkIndex.get(clazz));
            }
            if (childlist != null) {
                for (SuperVO vo : childlist) {
                    if (vo.getId() == null) {
                        vo.setId(UUID.randomUUID().toString().replaceAll("-", ""));
                    }
                    //没有外键
                    if (fk == null) {
                        continue;
                    }
                    String parentid = (String) fk.getValue(vo);
                    if (parentid == null) {
                        parentid = id;
                    }
                    fk.setValue(vo, parentid);
                }
            }
        }
    }

    private ClassField getFKField(Class<?> clazz, String name) {
        ClassFieldFinder finder = new ClassFieldFinder();
        Map<String, ClassField> index = finder.getAttributes(clazz);
        ClassField field = index.get(name);
        if (field == null) {
            String message = "外键属性不存在";
            ExceptionUtils.wrapBusinessException(message);
        }
        return field;
    }

    @Override
    public void delete(List<AbstractMeBillVO> list) {
        this.deleteBillRow(list);
    }

    private void deleteBillRow(List<AbstractMeBillVO> list) {
        BillTool tool = new BillTool();
        Map<Class<?>, List<SuperVO>> values = tool.group(list, EntityConst.DELETE);
        Set<Map.Entry<Class<?>, List<SuperVO>>> set = values.entrySet();
        for (Map.Entry<Class<?>, List<SuperVO>> entry : set) {
            List<SuperVO> volist = entry.getValue();
            if (volist == null || volist.size() == 0) {
                continue;
            }
            Class<?> key = entry.getKey();
            this.daoIndex.get(key).delete(volist);
        }
    }

    private void insertBillRow(List<AbstractMeBillVO> list) {
        BillTool tool = new BillTool();
        Map<Class<?>, List<SuperVO>> values = tool.group(list, EntityConst.INSERT);
        Set<Map.Entry<Class<?>, List<SuperVO>>> set = values.entrySet();
        for (Map.Entry<Class<?>, List<SuperVO>> entry : set) {
            List<SuperVO> volist = entry.getValue();
            if (volist == null || volist.size() == 0) {
                continue;
            }
            Class<?> key = entry.getKey();
            this.daoIndex.get(key).insert(volist);
        }
    }

    private void updateBillRow(List<AbstractMeBillVO> list) {
        BillTool tool = new BillTool();
        Map<Class<?>, List<SuperVO>> values = tool.group(list, EntityConst.UPDATE);
        Set<Map.Entry<Class<?>, List<SuperVO>>> set = values.entrySet();
        for (Map.Entry<Class<?>, List<SuperVO>> entry : set) {
            List<SuperVO> volist = entry.getValue();
            if (volist == null || volist.size() == 0) {
                continue;
            }
            Class<?> key = entry.getKey();
            this.daoIndex.get(key).update(volist);
        }
    }

    @Override
    public List<AbstractMeBillVO> insert(List<AbstractMeBillVO> list) {
        this.setIDAndFK(list);
        this.insertBillRow(list);
        return list;
    }

    private void setIDAndFK(List<AbstractMeBillVO> list) {
        for (AbstractMeBillVO bill : list) {
            this.setIDAndFK(bill);
        }
    }

    @Override
    public List<AbstractMeBillVO> update(List<AbstractMeBillVO> list) {
        this.setIDAndFK(list);

        this.insertBillRow(list);
        this.deleteBillRow(list);
        this.updateBillRow(list);

        //过滤已经删除行
        BillTool tool = new BillTool();
        tool.fileterBillDeleteRow(list);
        return list;
    }
}
